<?php
/**
 * 名称：Authorization
 * 功能：后台权限管理
 * 作者: Qiyuan<mqycn@126.com>
 * 更新：http://git.oschina.net/mqycn/thinkAuthorization5/
 */

namespace app\Admin\controller;

ini_set('max_execution_time', '0');

class Authorization extends _Admin {

	/**
	 * 权限分组列表
	 */
	public function index() {
		$AuthGroup = db("AuthGroup");
		$list = $AuthGroup->select();
		$this->assign("list", $list);

		unset($AuthGroup);
		return $this->fetch();
	}

	/**
	 * 添加权限分组
	 */
	public function add() {
		$default = [
			"ag_name" => "",
			"ag_login" => "",
			"ag_id" => 0,
			"ag_auth" => [],
		];
		return $this->edit($default);
	}

	/**
	 * 编辑权限分组
	 */
	public function edit($default = false) {

		$gid = $this->_gid();

		//初始化权限分组
	if ($default !== false) {
			$group = $default;
		} else {
			if ($gid == 0) {
				$this->error("要编辑的权限组不存在");
			}
			$AuthGroup = db("AuthGroup");
			$group = $AuthGroup->find($gid);
			if (!$group) {
				$this->error("要编辑的权限组不存在");
			}
			unset($AuthGroup);

			$group['ag_auth'] = unserialize($group['ag_auth']);

			if (!is_array($group['ag_auth'])) {
				$group['ag_auth'] = [];
			}

		}

		$authlist = $this->_GetAuthList($group['ag_auth']);

		$this->assign("group", $group);
		$this->assign("authlist", $authlist);

		unset($group, $authlist);

		return $this->fetch("edit");
	}

	/**
	 * 保存权限分组设置
	 */
	public function save() {

		$AuthGroup = db("AuthGroup");

		if (true !== $this->validate(['__token__' => input('post.__token__')], ['__token__' => 'token'])) {
			$this->error("请不要非法提交");
		}

		$gid = $this->_gid();
		$auth_array = isset($_POST['ag_auth']) ? $_POST['ag_auth'] : [];
		if (!is_array($auth_array)) {
			$auth_array = [];
		}
		$ag_auth = serialize($auth_array);
		$ag_name = htmlspecialchars(input('ag_name'));
		$ag_login = htmlspecialchars(input('ag_login'));
		if ($gid != 0) {
			if (!$AuthGroup->find($gid)) {
				$this->error("要操作的分组不存在");
			}
		}

		if ('' == $ag_name) {
			$this->error("对不起，分组名称不能为空");
		}

		$findgroup = $AuthGroup->where(["ag_name" => $ag_name])->find();

		if ($findgroup) {
			if ($findgroup['ag_id'] != $gid) {
				$this->error("对不起，分组[" . $ag_name . "]已经存在，请不要重复添加");
			}
		}
		unset($findgroup);

		$group = [
			"ag_name" => $ag_name,
			"ag_auth" => $ag_auth,
			"ag_login" => $ag_login,
		];

		if ($gid === 0) {
			$gid = $AuthGroup->insertGetId($group);
		} else {
			$group['ag_id'] = $gid;
			$AuthGroup->update($group);
		}

		cache('auth_group_' . $gid, $auth_array);
		unset($AuthGroup, $group, $auth_array);

		if ($gid === 0) {
			$this->success("保存成功", "index");
		} else {
			$this->success("保存成功", url("edit", ['gid' => $gid]));
		}
	}

	/**
	 * 删除权限分组
	 */
	public function delete() {
		$gid = $this->_gid();
		if ($gid < 2) {
			$this->error("内置分组不能删除");
		} else {
			$AuthGroup = db("AuthGroup");
			$where = ["ag_id" => $gid];
			if ($AuthGroup->where($where)->delete()) {
				$this->success("删除成功");
			} else {
				$this->success("删除失败，请重试");
			}

		}
	}

	/**
	 * 更新 Controller 和 Action
	 */
	public function update() {
		//ThinkPHP版本号
		$ver = explode(".", THINK_VERSION);
		$mode = "5.0";
		if ('5' == $ver[0]) {
			switch ($ver[1]) {
			case "0":
				$mode = "5.0";
				break;
			default:
				$this->error("当前版本不支持 ThinkPHP5." . $ver[1] . "，请升级最新版");
			}
		} else {
			$this->error("权限更新：暂时只支持ThinkPHP5.x");
		}

		//获取模块
		$AuthModule = db("AuthModule");
		if ($mode == "5.0") {
			//ThinkPHP5.0
			foreach ($AuthModule->select() as $module) {
				$this->_Update50($module);
			}
		} else {
			//根据版本不通，扩展不同的扫描方法
		}
		unset($AuthModule);

		$this->success("更新完毕", url("FriendlyName"));
	}

	/**
	 * 对扫描到的Controller 和 Action 自定义名称
	 */
	public function friendlyName() {
		$authlist = $this->_GetAuthList();
		$this->assign("authlist", $authlist);
		unset($authlist);
		return $this->fetch();
	}

	/**
	 * 保存 自定义名称
	 */
	public function saveFriendlyName() {

		if (true !== $this->validate(['__token__' => input('post.__token__')], ['__token__' => 'token'])) {
			$this->error("请不要非法提交");
		}

		$this->_SaveFriendly("AuthModule", "am_id", "am_name");
		$this->_SaveFriendly("AuthController", "ac_id", "ac_name");
		$this->_SaveFriendly("AuthAction", "aa_id", "aa_name");
		$this->success("保存自定义名称成功", url("friendlyName"));
	}

	/**
	 * ThinkPHP5.0 扫描
	 */
	private function _Update50($module) {
		$this->_UpdateCore($module, $module['am_path'] . "/controller/");
	}

	/**
	 * 扫描Controller
	 */
	private function _UpdateCore($module, $controller_path, $namespace = 'app\\') {
		$AuthController = db("AuthController");

		//所有 Controller 都不可用
		$where = ["ac_mid" => $module['am_id']];
		$data = ["ac_error" => 1];
		$AuthController->where($where)->update($data);

		//遍历 Controller 目录下的所有控制器
		$count = 0;
		$controllers_path = APP_PATH . $controller_path;

		foreach (scandir($controllers_path) as $file_name) {
			if ('.php' == substr($file_name, -4)) {
				$file_path = $controllers_path . $file_name;

				$count++;
				$controller_name = substr($file_name, 0, -4);

				if (substr($controller_name, 0, 1) != "_") {

					//根据控制器文件查询数据库中的控制器
					$where = [
						"ac_mid" => $module["am_id"],
						"ac_path" => $controller_name,
					];
					$controller = $AuthController->where($where)->find();
					if (!$controller) {
						$controller = $where;
						$controller['ac_name'] = $controller_name;
						$controller['ac_error'] = 0;
						$controller["ac_id"] = $AuthController->insertGetId($controller);
					} else {
						//控制器存在，更新为可用
						$controller['ac_error'] = 0;
						$AuthController->update($controller);
					}

					//载入类，设置类名称，准备下一步分析
					require_once $file_path;

					$controller['class'] = $namespace . $module['am_path'] . "\\controller\\" . $controller["ac_path"];

					$this->_UpdateAction($module, $controller);
				}
			}
		}

		//对不存的 模块，设置为 1
		$module['am_error'] = $count == 0 ? 1 : 0;
		db("AuthModule")->update($module);
		unset($AuthController);
	}

	/**
	 * 扫描Action
	 */
	private function _UpdateAction($module, $controller) {
		$AuthAction = db("AuthAction");

		//所有 Action 都不可用
		$where = ["aa_cid" => $controller['ac_id']];
		$data = ["aa_error" => 1];
		$AuthAction->where($where)->update($data);

		//遍历类，如果存在未定义的方法，则添加数据库
		$hideMothod = [

			//5.0 内置
			"beforeAction", "fetch", "display", "assign", "engine",
			"validateFailException", "validate", "success", "error",
			"result", "redirect", "getResponseType",

			//自定义

		];

		//遍历类的方法
		foreach (get_class_methods($controller['class']) as $method) {

			if (substr($method, 0, 1) == "_" || in_array($method, $hideMothod)) {
				// _开头， 或者 hideMothod 列表中的方法
			} else {

				//根据控制器文件查询数据库中的控制器
				$where = [
					"aa_cid" => $controller["ac_id"],
					"aa_path" => $method,
				];
				$action = $AuthAction->where($where)->find();
				if (!$action) {
					$action = $where;
					$action['aa_name'] = $method;
					$action['aa_error'] = 0;
					$action['aa_key'] = strtolower($module['am_path'] . "/" . $controller['ac_path'] . "/" . $method);
					$action["aa_id"] = $AuthAction->insertGetId($action);
				} else {
					//控制器存在，更新为可用
					$action['aa_error'] = 0;
					$AuthAction->update($action);
				}
			}
		}

		unset($AuthAction);
	}

	/**
	 * 输出权限列表
	 */
	private function _GetAuthList($_group = []) {
		//列出所有权限组
		$authlist = [];
		$AuthModule = db("AuthModule");
		$AuthController = db("AuthController");
		$AuthAction = db("AuthAction");

		$modules = $AuthModule->field("am_id,am_path,am_name")->select();

		foreach ($modules as $module) {
			$module['list'] = [];
			$controllers = $AuthController->where("ac_mid='" . $module['am_id'] . "'")->field("ac_id,ac_path,ac_name")->select();

			foreach ($controllers as $controller) {
				$controller['list'] = [];
				$actions = $AuthAction->where("aa_cid='" . $controller['ac_id'] . "'")->field("aa_id,aa_key,aa_path,aa_name")->select();
				foreach ($actions as $action) {
					$action['selected'] = in_array($action['aa_key'], $_group);
					$controller['list'][] = $action;
				}
				$module['list'][] = $controller;
			}
			$authlist[] = $module;
		}

		unset($AuthModule, $AuthController, $AuthAction);
		return $authlist;
	}

	/**
	 * 循环保存自定义名称（核心）
	 */
	private function _SaveFriendly($model, $id, $name) {
		$_ID = $_POST[$id];
		$_Name = $_POST[$name];
		if (is_array($_ID) && is_array($_Name)) {
			$_Model = db($model);
			foreach ($_ID as $index => $_id) {
				if (is_numeric($_id)) {
					$_name = htmlspecialchars($_Name[$index]);
					$item = [
						$id => $_id,
						$name => $_name,
					];
					$_Model->update($item);
				}
			}
			unset($_Model, $item);
		}
	}

	/**
	 * 快速获取 分组编号
	 */
	private function _gid() {
		$gid = input('gid');
		if (!is_numeric($gid)) {
			$gid = 0;
		} else {
			$gid = (int) $gid;
		}
		return $gid;
	}

}